﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TLD_Vision;

namespace TLD_Vision.filters
{
    public class Normalization
    {
        public static uint ToGrayscale(uint argb)
        {
            // ARGB stored in little-endian becomes BGRA
            unsafe
            {
                byte* bgra = (byte*)&argb;
                byte greyval = (byte)(0.21 * bgra[2] + 0.71 * bgra[1] + 0.07 * bgra[0]);
                return (uint)(bgra[3] << 24 | greyval << 16 | greyval << 8 | greyval);
            }
        }

        public static uint ExtractRed(uint argb)
        {
            return argb &= 0xFFFF0000;
        }

        public static uint ExtractGreen(uint argb)
        {
            return argb &= 0xFF00FF00;
        }

        public static uint ExtractBlue(uint argb)
        {
            return argb &= 0xFF0000FF;
        }

        public static SinglePixelOperation ColorHistogramEqualisation(Histogram hist)
        {
            double[] scalingFactor = new double[hist.Length];
            int numPixels = hist.Sum();
            double alpha = 255.0 / numPixels;

            scalingFactor[0] = hist[0] * alpha;
            for (int i = 1; i < hist.Length; i++)
            {
                scalingFactor[i] = scalingFactor[i - 1] + alpha * hist[i];
            }

            return delegate(uint argb)
            {
                unsafe
                {
                    byte* bgra = (byte*)&argb;
                    HSLValue hsl = Color.RGBtoHSL(bgra[2], bgra[1], bgra[0]);
                    hsl.lightness = scalingFactor[(int)(hsl.lightness * 255)] / 255;
                    byte[] rgb = Color.HSLtoRGB(hsl);
                    return (uint)(bgra[3] << 24 | rgb[0] << 16 | rgb[1] << 8 | rgb[0]);
                }
            };
        }

        public static SinglePixelOperation GreyscaleHistogramEqualisation(Histogram hist)
        {
            byte[] scalingFactor = new byte[hist.Length];
            int numPixels = hist.Sum();
            double alpha = 255.0 / numPixels;

            scalingFactor[0] = (byte)(hist[0] * alpha);
            for (int i = 1; i < hist.Length; i++)
            {
                scalingFactor[i] = (byte)(scalingFactor[i - 1] + alpha * hist[i]);
            }

            return delegate(uint argb)
            {
                unsafe
                {
                    byte* bgra = (byte*)&argb;
                    byte newval = scalingFactor[bgra[0]];
                    return (uint)(bgra[3] << 24 | newval << 16 | newval << 8 | newval);
                }
            };
        }
    }
}
